/****************************************************************************************
 * File:			Animat.cs
 * Description:		Implementation of an animat as a wrapper around a brain and a body.
 *                  Container class that stores the physical and cognitive parts of an 
 *					entity, and provides their maintenance.
 ***************************************************************************************/

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace XGAE.Framework
{
    /// <summary>
    /// A wrapper class primarily containing the Brain and the Body.  The Body is only 
    /// referenced, as it's handled by the platform.  The Brain is stored as an interface 
    /// providing an entry point for the control.  The Brain's internal structure is also 
    /// stored here by the Architecture.
    /// </summary>
    class Animat : IDisposable
    {
        #region Fields

        private Component m_body; // reference to the body defined by the platform
        private Component m_brain; // access to all the nested components
        private Architecture m_root; // base of the AI architecture in this scope
        private string m_directory; // name of this animat's directory
        private Services.IExecute m_think; //entry point to the brain of the animat

        // Track whether Dispose has been called.
        private bool disposed = false;

        #endregion

        #region C'tors

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="name">Name of the animat within the game.</param>
        /// <param name="body">Corresponding body in the game belonging to this animat.</param>
        public Animat(string name, Component body)
        {
            m_brain = null;
	        m_directory = (@"fear/animats/" + name);
	        m_body = body;
        }

        #endregion

        #region Pubic Methods

        /// <summary>
        /// Procedure lets the agent think, and catches potential errors.
        /// Call the only function of the execute interface, and catch any errors if any.
        /// </summary>
        /// <returns></returns>
        public bool Exist()
        {
            try
            {
                // process the sensory information and act appropriately
                m_think.Tick();
                // everything went ok
                return true;
            }
            catch (Exception ex)
            {
                // report problem appropriately, usually via stderr
                //Warning("General exception in component " + m_brain.GetType());
                // and tell the controller something went wrong so it can take action
                return false;
            }
        }

        /// <summary>
        /// Load the animat from its XML file in its own directory. The body is loaded, which consists mostly of 
        /// cosmetic attributes in the game (e.g. model gender and appearance).  The entry point to
        /// the brain is also defined here, so we know which type of brain is required.
        /// </summary>
        /// <returns>Boolean indicating the success of the operation.</returns>
        public bool Load()
        {
            #region old
            /*// parse the input string
            XmlDocument config = new XmlDocument();
            config.Load(m_directory + "Animat.xml");
            // scan all the components within the <animat> XML tag
            foreach (XmlNode childNode in config.DocumentElement.ChildNodes)
            {
                // this is the main node of interest
                if (childNode.Name == "brain")
                {
                    // create a new brain of the right type from the static factory
                    m_brain = Factory.Create(childNode.Attributes["type"].Name);
                    // now register the body with the brain so it can interact with the world
                    m_brain.Include("Backend", m_body);
                    // let the component know of the directory
                    XmlNode xn = config.CreateNode(XmlNodeType.Element, "directory", null);
                    xn.Value = m_directory;
                    childNode.InsertAfter(xn, childNode.LastChild);
                    // create the root architecture in this scope so other subarchitectures
		            // have access to all the components in the static factory 
		            m_root = new Architecture("Root");
                    // ask the brain to load itself recursively
                    m_brain.PreLoad(childNode, m_root);
                    // find the main entry point corresponding to the Think() method
                    m_think = (IExecute)m_brain.Export("Execute");
                    if (m_think==null)
                    {
                        //Warning("Execute interface not found for component " + (*i)["type"]);
                    }
                }

                // arbitrary attributes that affect the apperance of the body
                if (childNode.Name == "body")
                {
                    m_body.Load(childNode);
                }
            }*/
            #endregion

            Extensions.XmlDataTree data = new Extensions.XmlDataTree(m_directory + "Animat.xml");

            foreach (Extensions.XmlDataTree xdt in data.Branches)
            {
                if (xdt.Name == "brain")
                {
                    // create a new brain of the right type from the static factory
			        m_brain = Factory.Create(xdt.GetSecondLeaveByKey("type"));
                    // now register the body with the brain so it can interact with the world
                    m_brain.Include("Backend", m_body);
                    // let the component know of the directory
			        xdt.Branches.Add(new Extensions.XmlDataTree("directory", m_directory));
                    // create the root architecture in this scope so other subarchitectures
                    // have access to all the components in the static factory 
                    m_root = new Architecture("Root");
                    // ask the brain to load itself recursively
                    m_brain.PreLoad(xdt, m_root);
                    // find the main entry point corresponding to the Think() method
                    m_think = (Services.IExecute)m_brain.Export("Execute");
                    if (m_think == null)
                    {
                        //Warning("Execute interface not found for component " + (*i)["type"]);
                    }
                }

                // arbitrary attributes that affect the apperance of the body
                if (xdt.Name == "body")
                {
                    m_body.Load(xdt);
                }
            }

            return true;
        }

        /// <summary>
        /// Store the animat on disk by calling the brain to write itself into XML.
        /// Call the brain to save itself recursively as an architecture.
        /// </summary>
        /// <returns>Boolean indicating the success of the operation.</returns>
        public bool Save()
        {
	        m_brain.PreSave(new Extensions.XmlDataTree());	
	        return true;
        } 

        #endregion

        #region IDisposable Methods

        // Implement IDisposable.
        // Do not make this method virtual.
        // A derived class should not be able to override this method.
        public void Dispose()
        {
            Dispose(true);
            // This object will be cleaned up by the Dispose method.
            // Therefore, you should call GC.SupressFinalize to
            // take this object off the finalization queue
            // and prevent finalization code for this object
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

        // Dispose(bool disposing) executes in two distinct scenarios.
        // If disposing equals true, the method has been called directly
        // or indirectly by a user's code. Managed and unmanaged resources
        // can be disposed.
        // If disposing equals false, the method has been called by the
        // runtime from inside the finalizer and you should not reference
        // other objects. Only unmanaged resources can be disposed.
        private void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if (!this.disposed)
            {
                // If disposing equals true, dispose all managed
                // and unmanaged resources.
                //if (disposing)
                //{
                    // Dispose managed resources.
                    // tell the registry to free the brain
                    if (m_brain != null)
                        Factory.Delete(m_brain);
                    m_brain = null;
                //}

                // Note disposing has been done.
                disposed = true;
            }
        }

        // Use C# destructor syntax for finalization code.
        // This destructor will run only if the Dispose method
        // does not get called.
        // It gives your base class the opportunity to finalize.
        // Do not provide destructors in types derived from this class.
        ~Animat()
        {
            // Do not re-create Dispose clean-up code here.
            // Calling Dispose(false) is optimal in terms of
            // readability and maintainability.
            Dispose(false);
        }

        #endregion
    }
}
